module allocator_mod
	
	use const_mod
	use mesh_mod

	implicit none

	private
	public allocate_array

	interface allocate_array
		module procedure allocate_array_2d_r8
		module procedure allocate_array_3d_r8
	end interface allocate_array

contains

	subroutine allocate_array_2d_r8(mesh, array, full_lon, half_lon, full_lat, half_lat)

		type(mesh_type), intent(in )              :: mesh
		real(r8)       , intent(out), allocatable :: array(:,:)
		logical        , intent(in ), optional    :: full_lon
		logical        , intent(in ), optional    :: half_lon
		logical        , intent(in ), optional    :: full_lat
		logical        , intent(in ), optional    :: half_lat
		logical full_lon_, half_lon_, full_lat_, half_lat_

		if (present(full_lon)) then
			full_lon_ = full_lon
		else
		  full_lon_ = .false.
		end if
		if (present(half_lon)) then 
			half_lon_ = half_lon
		else 
			half_lon_ = .false.
		end if
		if (present(full_lat)) then
			full_lat_ = full_lat
		else 
			full_lat_ = .false.
		end if
		if (present(half_lat)) then
			half_lat_ = half_lat
		else 
			half_lat_ = .false.
		end if

		if (full_lon_ .and. full_lat_) then 
			allocate(array(mesh%full_lon_lb:mesh%full_lon_ub, mesh%full_lat_lb:mesh%full_lat_ub))
		else if (full_lon_ .and. half_lat_) then
			allocate(array(mesh%full_lon_lb:mesh%full_lon_ub, mesh%half_lat_lb:mesh%half_lat_ub))
		else if (half_lon_ .and. full_lat_) then 
			allocate(array(mesh%half_lon_lb:mesh%half_lon_ub, mesh%full_lat_lb:mesh%full_lat_ub))
		else if (half_lon_ .and. half_lat_) then
			allocate(array(mesh%half_lon_lb:mesh%half_lon_ub, mesh%half_lat_lb:mesh%half_lat_ub))
		end if 
		array = 0.0_r8

	end subroutine allocate_array_2d_r8

	subroutine allocate_array_3d_r8(mesh, array, full_lon, half_lon, full_lat, half_lat, full_lev, half_lev)

		type(mesh_type), intent(in )              :: mesh
		real(r8)       , intent(out), allocatable :: array(:,:,:)
		logical        , intent(in ), optional    :: full_lon
		logical        , intent(in ), optional    :: half_lon
		logical        , intent(in ), optional    :: full_lat
		logical        , intent(in ), optional    :: half_lat
		logical        , intent(in ), optional    :: full_lev
		logical        , intent(in ), optional    :: half_lev
		logical full_lon_, half_lon_, full_lat_, half_lat_, full_lev_, half_lev_

		if (present(full_lon)) then
			full_lon_ = full_lon
		else
			full_lon_ = .false.
		end if
		if (present(half_lon)) then
			half_lon_ = half_lon
		else
			half_lon_ = .false.
		end if
		if (present(full_lat)) then
			full_lat_ = full_lat
		else
			full_lat_ = .false.
		end if
		if (present(half_lat)) then
			half_lat_ = half_lat
		else 
			half_lat_ = .false.
		end if
		if (present(full_lev)) then
			full_lev_ = full_lev
		else 
			full_lev_ = .false.
		end if
		if (present(half_lev)) then
			half_lev_ = half_lev
		else 
			half_lev_ = .false.
		end if

		if (full_lon_ .and. full_lat_ .and. full_lev_) then
			allocate(array(mesh%full_lon_lb:mesh%full_lon_ub, mesh%full_lat_lb:mesh%full_lat_ub, mesh%full_lev_lb:mesh%full_lev_ub))
		else if (full_lon_ .and. half_lat_ .and. full_lev_) then
			allocate(array(mesh%full_lon_lb:mesh%full_lon_ub, mesh%half_lat_lb:mesh%half_lat_ub, mesh%full_lev_lb:mesh%full_lev_ub))
		else if (half_lon_ .and. full_lat_ .and. full_lev_) then
			allocate(array(mesh%half_lon_lb:mesh%half_lon_ub, mesh%full_lat_lb:mesh%full_lat_ub, mesh%full_lev_lb:mesh%full_lev_ub))
		else if (half_lon_ .and. half_lat_ .and. full_lev_) then
			allocate(array(mesh%half_lon_lb:mesh%half_lon_ub, mesh%half_lat_lb:mesh%half_lat_ub, mesh%full_lev_lb:mesh%full_lev_ub))
		end if 

		if (full_lon_ .and. full_lat_ .and. half_lev_) then
			allocate(array(mesh%full_lon_lb:mesh%full_lon_ub, mesh%full_lat_lb:mesh%full_lat_ub, mesh%half_lev_lb:mesh%half_lev_ub))
		else if (full_lon_ .and. half_lat_ .and. half_lev_) then
			allocate(array(mesh%full_lon_lb:mesh%full_lon_ub, mesh%half_lat_lb:mesh%half_lat_ub, mesh%half_lev_lb:mesh%half_lev_ub))
		else if (half_lon_ .and. full_lat_ .and. half_lev_) then
			allocate(array(mesh%half_lon_lb:mesh%half_lon_ub, mesh%full_lat_lb:mesh%full_lat_ub, mesh%half_lev_lb:mesh%half_lev_ub))
		else if (half_lon_ .and. half_lat_ .and. half_lev_) then
			allocate(array(mesh%half_lon_lb:mesh%half_lon_ub, mesh%half_lat_lb:mesh%half_lat_ub, mesh%half_lev_lb:mesh%half_lev_ub))
		end if 		
		array = 0.0_r8

	end subroutine allocate_array_3d_r8

end module allocator_mod